後續要來實作登入的相關功能。這次打算來使用 JWT 的機制。
一般最常見的登入方式,就是使用 session 機制,也就是會在伺服器端,儲存 session 資訊,這個 session 機制,可以是一個用檔案儲存的形式;也可以是將 session 內容儲存在資料庫中。
無論是哪一種形式,重點在於會在伺服器端儲存 session。然後在使用者端(瀏覽器),使用 cookie 方式,儲存 Session ID,用來跟伺服器端的 Session 做對應,達到登入驗證的功能。
如果今天是個規模不大的網站,也就是網站只儲存在一台伺服器上,那使用 session 的機制其實也沒什麼太大的問題,很夠用,一般的官網其實用這個方式即可。
但如果今天網站可能成長到了一個規模,單一伺服器的方式,可能會無法容納大量的在線人數、或者說無法應付大量的 requests 數量。那就會需要做流量上的分流,也就是網站會佈署至多台的伺服器。
此時 session 的登入機制,就會遇到麻煩了,因為若 session 只儲存在某一台伺服器的話,使用者可能登入之後,再重新整理頁面,會變成沒有登入,因為連到的是另一台伺服器。
解決方式呢,那就是會想辦法將 session 做所有伺服器的同步,或者另外獨立一台伺服器,專門管理 session(無論是用檔案形式或資料庫形式)。總之,就是個麻煩。
JSON Web Tokens 的官網,有些介紹。
簡單來說呢,也就是不使用 session 的機制了,那麼在伺服器端,理所當然的,就不會儲存 session 任何內容,這樣就達到一般大家所說的伺服器無狀態(stateless)。那麼原來存在伺服器端的資訊,會存在哪呢?那當然就是 client 端(瀏覽器端)。
這樣即使有多台伺服器,也不會造成像上述所說的:「登入之後再重新整理頁面,可能變成沒有登入」。
使用 JWT 機制,最後產出的結果,就是一個字串,格式如下:
HEADER.PAYLOAD.SIGNATURE
是由以下的物件:
{
"alg": "HS256",
"typ": "JWT"
}
alg 中的 HS256,可以改成其它想要設定的加密演算法。然後這個物件需經由 Base64Url 來轉成某字串形式。
就是想要傳遞的資料,也是一個物件,有一些 key 的名稱有特定用途,相關說明可參考這個網址的 Payload 部份。
例如一個 PAYLOAD 資訊如下:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
這個 簽名(SIGNATURE) 的產生呢,就是拿上述的 HEADER 跟 PAYLOAD,以及一個自訂的 secret(或 private key),然後使用 HEADER 當中所定義的演算法(alg 那個 key),最後產出 簽名(SIGNATURE)。
經由以上的說明,就是可以產出 JSON Web Tokens(JWT),它就是個字串,再提一次,格式如下:
HEADER.PAYLOAD.SIGNATURE
這個 JWT 呢,就是通常在登入時,如果伺服器驗證通過(即登入成功),就會產生這樣的 JWT, 回傳給 client 端儲存起來,然後 client 端每次在 call 伺服器的一些 API 功能時,就會帶這個 JWT 放在表頭資訊中一起傳出,例:
Authorization: Bearer JWT放這
然後伺服器端就會檢查該 JWT 是否是合法的 token,如果是的話,就可以進一步的執行其它功能。
很多跨網域的 SSO(Single Sign-On) 機制就會使用 JWT 這樣的機制。而且也避免了 session 所造成的問題。
這是我看完一些資料之後,所做的一些結論,若有誤的話,也歡迎讀者指正一下。後續我想用 JWT 機制,來實作登入的部份,因為我覺得 session 在同步上,真的是個麻煩的問題。過去會使用 Redis 來儲存 session,但滿不想在用此方式。